#include <string_view>

#include "IExtendDeviceManager.h"
#include "GuiContext.h"
#include "CodeScanner.h"
#include "PowerMonitor.h"
#include "DoorAlertor.h"
#include "AcSwitchDetector.h"
#include "ConfigManager.h"
#include "CurrentVoltageManager.h"
#include "LoopController.h"
#include "AcDetector.h"
#include "VideoController.h"
#include "ExtendLoopController.h"
#include "TouchPadController.h"
#include "GpsLuxSensor.h"
#include "InnerTemperatureMonitor.h"
#include "DoorAcSwitchDetector.h"


IExtendDeviceManager::IExtendDeviceManager(DeviceCommunicator& oCommunicator) :  mpool(GuiContextSingleton::instance().getWorkPool())
, mconfigManager(ConfigManagerSingleton::instance()), outerCommunicator(oCommunicator) {
    mrefreshFunction = std::bind(&IExtendDeviceManager::adjustDevice, this);
    mrefreshTask = Task{TaskType_t::CALLBACK, &mrefreshFunction};
}

IExtendDeviceManager::~IExtendDeviceManager() {
    //dtor
}


void IExtendDeviceManager::initialize() {
    try {
        innerCommunicator.setPort(StringUtility::EMPTY_STRING);
//        outerCommunicator.setPort(StringUtility::EMPTY_STRING);

        channelDevicesArray[0].first = ChannelUniquePtr(new MD::INNER_CHANNEL(0, innerCommunicator));
        for (int i = 1; i < MDConst::DEFAULT_CHANNEL_COUNT; ++i) {//
            channelDevicesArray[i].first = ChannelUniquePtr(new MD::OUTER_CHANNEL(i, outerCommunicator));//
        }

        ExtendDevice* pExtendDevice = new LoopController(*channelDevicesArray->first, ExtendDeviceEnum::CIRCUIT_ELEC, "CIRCUIT_ON/OFF_CH12_DATA_OK", 0, MDConst::DEFAULT_INTERNAL_LOOP_COUNT);
        addDevice(*channelDevicesArray, pExtendDevice);

        pExtendDevice = new InnerTemperatureMonitor(ExtendDeviceEnum::TEMPERATURE);

        addInnerDevice(pExtendDevice);

        adjustDevice();

        mallOnlineDevice[0] = ExtendDeviceWeakPtr(channelDevicesArray->second.front());

        getWorkThread().start();

    } catch (std::system_error& systemError) {
        LOG_ERROR(systemError.what());
    }
}

void IExtendDeviceManager::finish() {
    getWorkThread().stop();
}



ssize_t IExtendDeviceManager::createAndAddExtendDevice(const std::string& checkDeviceInfo, ChannelDevices& channelDevices) {

    ssize_t count = 1;
    if (checkDeviceInfo.empty()) {
        count = 0;
    } else {
        ExtendDevice* deviceController = nullptr;
        DummyChannel& channel = *channelDevices.first;
        std::string::size_type deviceNameIndex = checkDeviceInfo.find('_');
        std::string deviceName = checkDeviceInfo.substr(0, deviceNameIndex);
        if ("<EXTE_CURRENT_DATA_OK>" == checkDeviceInfo) {
            deviceController = new AcDetector(channel, ExtendDeviceEnum::ELECT, checkDeviceInfo, 0, MDConst::DEFAULT_INTERNAL_LOOP_COUNT);
        } else if ("<AT_VIDEOSERVER>" == checkDeviceInfo){
            deviceController = new VideoController(channel, ExtendDeviceEnum::VIDEO_CONTROLLER, checkDeviceInfo);
        } else if ("<SCANQRCODE" == deviceName) {
            deviceController = new CodeScanner(channel, ExtendDeviceEnum::CODE_SCANNER, checkDeviceInfo);
        } else if ("<POWER" == deviceName) {
            deviceController = new PowerMonitor(channel, ExtendDeviceEnum::POWER, checkDeviceInfo);
        } else if ("<DOORALERTOR" == deviceName) {
            deviceController = new DoorAlertor(channel, ExtendDeviceEnum::DOOR_ALERTOR, checkDeviceInfo);
        } else if ("<ACSWITCHDETECTOR" == deviceName) {
            deviceController = new AcSwitchDetector(channel, ExtendDeviceEnum::AC_SWITCH_DETECTOR, checkDeviceInfo);
        }
        else if ("<EXTENDCIRCUIT" == deviceName) {
            deviceController = new ExtendLoopController(channel, ExtendDeviceEnum::EX_CIRCUIT, checkDeviceInfo);
        } else if ("<AIRCIRCUIT" == deviceName) {
            deviceController = new ExtendLoopController(channel, ExtendDeviceEnum::AIR_CIRCUIT, checkDeviceInfo);
        } else if ("<TOUCHPAD" == deviceName) {
            deviceController = new TouchPadController(channel, ExtendDeviceEnum::TOUCHPAD_CONTROLLER, checkDeviceInfo);
        } else if ("<LUXGPS" == deviceName) {
            deviceController = new GpsLuxSensor(channel, ExtendDeviceEnum::GPS_LUX, checkDeviceInfo);
        }else if ("<GPS" == deviceName) {
            deviceController = new GpsSensor(channel, ExtendDeviceEnum::GPS, checkDeviceInfo);
        }


        if (nullptr != deviceController) {
            if (std::string::npos != deviceNameIndex){
                std::string::size_type endIndex = checkDeviceInfo.find('_', deviceNameIndex + 1);
                if (std::string::npos != endIndex){
                    deviceController->mversionString = checkDeviceInfo.substr(deviceNameIndex + 1, endIndex - deviceNameIndex - 1);
                }
            }

            addDevice(channelDevices, deviceController);
        }
    }

    return count;
}



ssize_t IExtendDeviceManager::findExtendDevice(ChannelDevices& channelDevices) {
    DummyChannel& channel = *channelDevices.first;
    std::string checkDeviceInfo;
    ExtendDevice::check(channel, checkDeviceInfo);//todo fix the multi device controller repeat

    return createAndAddExtendDevice(checkDeviceInfo, channelDevices);
}



void IExtendDeviceManager::adjustDevice() {

    std::vector<ExtendDeviceWeakPtr>::iterator current;
    //    std::vector<ExtendDeviceWeakPtr>::iterator end;
    for (std::unordered_map<const ExtendDeviceType*, std::vector<ExtendDeviceWeakPtr>>::value_type& entry: mtypeToExtendDevice) {
        current = entry.second.begin();

        while (current != entry.second.end()) {
            if ((*current).expired()) {
                current = entry.second.erase(current);
            } else {
                ++current;
            }
        }
    }

    for (ExtendDevicePtr& pExtendDevice : mnewOnlineDevice) {
        if (false == pExtendDevice->initialize()){
            continue;
        }
        if (pExtendDevice->mdeviceType.functionModule.empty()) {
            mtypeToExtendDevice[&pExtendDevice->mdeviceType].emplace_back(pExtendDevice);
        } else {
            for (const ExtendDeviceType* deviceType : pExtendDevice->mdeviceType.functionModule) {
                mtypeToExtendDevice[deviceType].emplace_back(pExtendDevice);
            }
        }
    }

    std::vector<ExtendDeviceWeakPtr>& currentVoltageControllers = mtypeToExtendDevice.at(&ExtendDeviceEnum::ELECT);
    size_t size = currentVoltageControllers.size();
    if (1 < size) {
        std::vector<ExtendDeviceWeakPtr>::iterator findIterator = std::find(currentVoltageControllers.begin(), currentVoltageControllers.end(), ExtendDeviceWeakPtr(channelDevicesArray->second.front()));
        currentVoltageControllers.erase(findIterator);

    } else if (0 == size) {
        currentVoltageControllers.emplace_back(mallOnlineDevice[0]);
    }

    bool noDevice = true;
    for (int i = 1; i < MDConst::DEFAULT_CHANNEL_COUNT; ++i) {
        if (channelDevicesArray[i].second.empty()) {
            continue;
        }
        noDevice = false;
        mallOnlineDevice[i] = channelDevicesArray[i].second.front();
    }

//    if (noDevice){
//        BuzzerSingleton::instance().beep(BuzzerDataPtr(new BuzzerDataPtr::element_type{1000000}));
//    }

}




